#ifndef UTILS_CPP_
#define UTILS_CPP_

#define DEBUG 0

#include "Utils.h"
#include <fstream>
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <sstream>
#include <stdlib.h>

using namespace std;

//Initialization functions
int readDppmSpec(char* filePath, int &numAct, int &T, int* &numPreds, int** &Preds, int* &numModes, int** &ModesCosts, int** &ModesTimes){
//
//	int debug=1;
//	while(debug);

	ifstream file;
	string line;
	file.open(filePath);

	if (!file.is_open()){
		return -1;
	}

	if (getline(file,line) == 0){
		return -1;
	}

	int lineNumber = 0;

	//Leer fila1: Numero de actividades y deadline
	sscanf(line.data(),"%d %d",&numAct,&T);

	lineNumber++;
	if (DEBUG){
		cout << lineNumber << ":\"" << line.data() << "\"\n";
		cout << "    numAct = \"" << numAct << "\"\n";
		cout << "    T = \"" << T << "\"\n";
		cout << "--------------------------------\n\n";
	}

	getline(file,line);
	getline(file,line);
	lineNumber++;
	lineNumber++;

	//Inicializar arreglo de predecesores
	Preds = new int*[numAct];
	numPreds = new int[numAct];

	//auxiliares
	int pred;
	int preds[1000];
	char* lineCopy;
	char* rest;

	for (int i = 0; i < numAct; i++){

		getline(file,line);
		lineCopy = new char[strlen(line.data()) + 1];
		strcpy(lineCopy, line.data());
		rest = lineCopy;

		numPreds[i] = 0;

		if (strcmp(rest," .")){
			do{
				sscanf(rest,"%d %[^\n]",&pred,rest);
				preds[numPreds[i]] = pred;
				numPreds[i]++;
			}while (strcmp(rest,"."));
		}

		if (numPreds[i] == 0){
			Preds[i] = NULL;
		}
		else{
			Preds[i] = new int[numPreds[i]];

			for(int j = 0; j < numPreds[i]; j++){
				Preds[i][j] = preds[j];
			}
		}

		delete [] lineCopy;

		lineNumber++;
		if (DEBUG){
			cout << lineNumber << ":\"" << line.data() << "\"\n";
			cout << "    cantPreds = \"" << numPreds[i] << "\"\n";
			cout << "--------------------------------\n\n";
		}
	}


	getline(file,line);
	getline(file,line);
	lineNumber++;
	lineNumber++;


	//Inicializar arreglos de modos
	ModesCosts = new int*[numAct];
	ModesTimes = new int*[numAct];
	numModes = new int[numAct];

	//auxiliares
	int cost, time;
	int modestimes[1000];
	int modescosts[1000];

	for (int i = 0; i < numAct; i++){
		getline(file,line);
		lineCopy = new char[strlen(line.data()) + 1];
		strcpy(lineCopy, line.data());
		rest = lineCopy;

		numModes[i] = 0;

		if (strcmp(rest," .")){
			do{
				sscanf(rest,"(%d,%d) %[^\n]",&cost,&time,rest);
				modescosts[numModes[i]] = cost;
				modestimes[numModes[i]] = time;
				numModes[i]++;
			}while (strcmp(rest,"."));
		}

		if (numModes[i] == 0){
			ModesCosts = NULL;
			ModesTimes = NULL;
		}
		else{
			ModesCosts[i] = new int[numModes[i]];
			ModesTimes[i] = new int[numModes[i]];

			for(int j = 0; j < numModes[i]; j++){
				ModesCosts[i][j] = modescosts[j];
				ModesTimes[i][j] = modestimes[j];
			}
		}

		delete [] lineCopy;

		lineNumber++;
		if (DEBUG){
			cout << lineNumber << ":\"" << line.data() << "\"\n";
			cout << "    cantModes = \"" << numModes[i] << "\"\n";
			cout << "--------------------------------\n\n";
		}
	}

	file.close();

	return 0;
}

int defineIndexesParams(DppmSpec * dppm, int &indLen, int * &indBases){

	int numAct = dppm->getNumActivities();
	indLen = numAct < MAX_INDEX_LENGTH ? numAct : MAX_INDEX_LENGTH;
	indBases = new int[indLen];
	indBases[indLen - 1] =  1;

	for(int i = indLen - 2; i >= 0; i--){
		indBases[i] = indBases[i+1] * dppm->getActivityNumModes(i+1);
	}

	return 0;

}


Tuple * makeTupleFromModes(DppmSpec * dppm, int * tupleModes){

	int numAct = dppm->getNumActivities();

	Tuple * t = new Tuple();
	int * iter = t->getArray();

	int numPreds = 0;
	int * preds = NULL;
	int maxTimePreds;

	for(int i = 0; i < numAct; i++){

		t->modes(i, tupleModes[i]);

		numPreds = dppm->getActivityNumPreds(i);
		preds = dppm->getActivityPreds(i);

		maxTimePreds = 0;

		for(int j = 0; j < numPreds; j++){

			if(maxTimePreds < t->times(preds[j]) ){
				maxTimePreds = t->times(preds[j]);
			}
		}


		t->times(i, maxTimePreds + dppm->getActivityModeTime(i, t->modes(i)) );

		if((i == 0) || (t->partialTimes(i - 1) < t->times(i))){
			t->partialTimes(i, t->times(i));
		}else{
			t->partialTimes(i, t->partialTimes(i - 1));
		}

		if(t->empty()){
			t->cost( dppm->getActivityModeCost(i, t->modes(i)) );
		}else{
			t->cost( t->cost() + dppm->getActivityModeCost(i, t->modes(i)) );
		}

	}

	return t;
}


int modesToIndex(int * modes, int indLen, int * indBases){

	int index = modes[0] * indBases[0];

	for(int i = 1; i < indLen; i++){
		index += modes[i] * indBases[i];
	}

	return index;

}


int * indexToModes(int index, int indLen, int * indBases, DppmSpec * dppm, int fillOutOption){

	int * modes = new int[dppm->getNumActivities()];

	for(int i = 0 ; i < indLen ; i++){

		modes[i] = index / indBases[i];
		index = index % indBases[i];

	}

	if (fillOutOption == FILL_WITH_FIRST_MODES){

		for(int i = indLen; i < dppm->getNumActivities(); i++){
			modes[i] = 0;
		}

	}else{

		for(int i = indLen; i < dppm->getNumActivities(); i++){
			modes[i] = dppm->getActivityNumModes(i) - 1;
		}

	}

	return modes;

}

int evalSolution(Tuple * candidate, Tuple * &bestSolution){

	if (bestSolution->cost() <= candidate->cost()){
		return 0;
	}else{
		delete bestSolution;
		bestSolution = new Tuple(candidate);
		return 1;
	}
}

int evalSolution(int * candidate, Tuple * &bestSolution){

	if (bestSolution->cost() <= Tuple::GetCostFromTupleArray(candidate)){
		return 0;
	}else{
		delete bestSolution;
		bestSolution = new Tuple(Tuple::tuplesIntSize, candidate);
		return 1;
	}
}

// Debug Functions
void debugPrinter(int identacion, int rank, const char * archivo, int linea, const char * desc){
//
	stringstream output;

	for (int i = 0; i < identacion; i++)
		output << "\t";

	output << "DEBUG  " << rank << "  " << archivo << ":" << linea << " -  " << desc << "\n";

	cout << output.str();
}

void debugPrinter(int identacion, int rank, const char * archivo, int linea, const char * desc, const char * var1Name, double var1){
//
	stringstream output;

	for (int i = 0; i < identacion; i++)
		output << "\t";

	output << "DEBUG  " << rank << "  " << archivo << ":" << linea << " -  " << desc << "   " << var1Name << "=" << var1 << "\n";

	cout << output.str();
}

void debugPrinter(int identacion, int rank, const char * archivo, int linea, const char * desc,  const char * var1Name, double var1, const char * var2Name, double var2){

	stringstream output;

	for (int i = 0; i < identacion; i++)
		output << "\t";

	output << "DEBUG  " << rank << "  " << archivo << ":" << linea << " -  " << desc << "   " << var1Name << "=" << var1 << "   " << var2Name << "=" << var2 << "\n";

	cout << output.str();

}

void debugPrinter(int identacion, int rank, const char * archivo, int linea, const char * desc,  const char * var1Name, int var1, const char * var2Name, int var2){

	stringstream output;

	for (int i = 0; i < identacion; i++)
		output << "\t";

	output << "DEBUG  " << rank << "  " << archivo << ":" << linea << " -  " << desc << "   " << var1Name << "=" << var1 << "   " << var2Name << "=" << var2 << "\n";

	cout << output.str();

}

void debugPrinter(int identacion, int rank, const char * archivo, int linea, const char * desc,
		const char * var1Name, double var1, const char * var2Name, double var2, const char * var3Name, double var3){

	for (int i = 0; i < identacion; i++)
		cout << "\t";

	cout << "DEBUG  " << rank << "  " << archivo << ":" << linea << " -  " << desc << "   " << var1Name << "=" << var1 << "   " << var2Name << "=" << var2 << "   " << var3Name << "=" << var3 <<endl;


}

void debugPrinter(int identacion, int rank, const char * archivo, int linea, const char * desc,
		const char * var1Name, int var1, const char * var2Name, int var2, const char * var3Name, int var3,
		 const char * var4Name, int var4){

	for (int i = 0; i < identacion; i++)
		cout << "\t";

	cout << "DEBUG  " << rank << "  " << archivo << ":" << linea << " -  " << desc << "   " << var1Name << "=" << var1 << "   " << var2Name << "=" << var2 << "   " << var3Name << "=" << var3 <<"   " << var4Name << "=" << var4 <<endl;


}

#endif /* UTILS_CPP_ */
